{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Reinplementation of Block Coordinate Descent (BCD) Algorithm for Training DNNs (3-layer MLP) for MNIST in PyTorch"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Import libraries"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "\"\"\"\n",
    "5 runs, seed = 10, 20, 30, 40, 50; \n",
    "validation accuracies: 0.9541, 0.9551, 0.9558, 0.9553, 0.9564\n",
    "\"\"\"\n",
    "from __future__ import print_function, division\n",
    "import numpy as np\n",
    "import pandas as pd\n",
    "import torch\n",
    "import torch.nn as nn\n",
    "import torch.nn.functional as F\n",
    "from torch.autograd import Variable\n",
    "import torch.optim as optim\n",
    "import torchvision\n",
    "from torchvision import datasets, models, transforms, utils\n",
    "from torch.utils.data import Dataset, DataLoader\n",
    "import matplotlib.pyplot as plt\n",
    "import time\n",
    "import os\n",
    "import copy\n",
    "\n",
    "# print(\"PyTorch Version: \",torch.__version__)\n",
    "# print(\"Torchvision Version: \",torchvision.__version__)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Read in MNIST dataset"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "dtype = torch.float\n",
    "device = torch.device(\"cpu\") # Uncomment this to run on CPU\n",
    "# device = torch.device(\"cuda:0\") \n",
    "\n",
    "# Convert to tensor and scale to [0, 1]\n",
    "ts = transforms.Compose([transforms.ToTensor(), \n",
    "                             transforms.Normalize((0,), (1,))])\n",
    "mnist_trainset = datasets.MNIST('../data', train=True, download=True,\n",
    "                       transform=ts)\n",
    "mnist_testset = datasets.MNIST(root='../data', train=False, download=True, \n",
    "                        transform=ts)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Data manipulation"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Manipulate train set\n",
    "x_d1 = mnist_trainset[0][0].size()[1]\n",
    "x_d2 = mnist_trainset[0][0].size()[2]\n",
    "N = x_d3 = len(mnist_trainset)\n",
    "K = 10\n",
    "x_train = torch.empty((N,x_d1*x_d2), device=device)\n",
    "y_train = torch.empty(N, dtype=torch.long)\n",
    "for i in range(N): \n",
    "     x_train[i,:] = torch.reshape(mnist_trainset[i][0], (1,x_d1*x_d2))\n",
    "     y_train[i] = mnist_trainset[i][1]\n",
    "x_train = torch.t(x_train)\n",
    "y_one_hot = torch.zeros(N, K).scatter_(1, torch.reshape(y_train,(N,1)), 1)\n",
    "y_one_hot = torch.t(y_one_hot).to(device=device)\n",
    "\n",
    "# Manipulate test set\n",
    "x_d1_test = mnist_testset[0][0].size()[1]\n",
    "x_d2_test = mnist_testset[0][0].size()[2]\n",
    "N_test = x_d3_test = len(mnist_testset)\n",
    "x_test = torch.empty((N_test,x_d1*x_d2), device=device)\n",
    "y_test = torch.empty(N_test, dtype=torch.long)\n",
    "for i in range(N_test): \n",
    "     x_test[i,:] = torch.reshape(mnist_testset[i][0], (1,x_d1*x_d2))\n",
    "     y_test[i] = mnist_testset[i][1]\n",
    "x_test = torch.t(x_test)\n",
    "y_test_one_hot = torch.zeros(N_test, K).scatter_(1, torch.reshape(y_test,(N_test,1)), 1)\n",
    "y_test_one_hot = torch.t(y_test_one_hot).to(device=device)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Main algorithm (Jinshan's Algorithm in Zeng et al (2018))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Parameter initialization"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "torch.manual_seed(50)\n",
    "d0 = x_d1*x_d2\n",
    "d1 = d2 = d3 = 2048\n",
    "d4 = K # Layers: input + 3 hidden + output\n",
    "W1 = 0.01*torch.randn(d1, d0, device=device)\n",
    "b1 = 0.1*torch.ones(d1, 1, device=device)\n",
    "W2 = 0.01*torch.randn(d2, d1, device=device)\n",
    "b2 = 0.1*torch.ones(d2, 1, device=device)\n",
    "W3 = 0.01*torch.randn(d3, d2, device=device)\n",
    "b3 = 0.1*torch.ones(d3, 1, device=device)\n",
    "W4 = 0.01*torch.randn(d4, d3, device=device)\n",
    "b4 = 0.1*torch.ones(d4, 1, device=device)\n",
    "\n",
    "U1 = torch.addmm(b1.repeat(1, N), W1, x_train)\n",
    "V1 = nn.ReLU()(U1)\n",
    "U2 = torch.addmm(b2.repeat(1, N), W2, V1)\n",
    "V2 = nn.ReLU()(U2)\n",
    "U3 = torch.addmm(b3.repeat(1, N), W3, V2)\n",
    "V3 = nn.ReLU()(U3) \n",
    "U4 = torch.addmm(b4.repeat(1, N), W4, V3)\n",
    "V4 = U4\n",
    "\n",
    "gamma = 1\n",
    "gamma1 = gamma2 = gamma3 = gamma4 = gamma\n",
    "\n",
    "rho = gamma\n",
    "rho1 = rho2 = rho3 = rho4 = rho\n",
    "\n",
    "\n",
    "alpha = 5\n",
    "alpha1 = alpha2 = alpha3 = alpha4 = alpha5 = alpha6 = alpha7 \\\n",
    "= alpha8 = alpha9 = alpha10 = alpha\n",
    "\n",
    "niter = 30\n",
    "loss1 = np.empty(niter)\n",
    "loss2 = np.empty(niter)\n",
    "accuracy_train = np.empty(niter)\n",
    "accuracy_test = np.empty(niter)\n",
    "time1 = np.empty(niter)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Define functions for updating blocks"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "def updateV_js(U1,U2,W,b,rho,gamma): \n",
    "    _, d = W.size()\n",
    "    I = torch.eye(d, device=device)\n",
    "    U1 = nn.ReLU()(U1)\n",
    "    _, col_U2 = U2.size()\n",
    "    Vstar = torch.mm(torch.inverse(rho*(torch.mm(torch.t(W),W))+gamma*I), rho*torch.mm(torch.t(W),U2-b.repeat(1,col_U2))+gamma*U1)\n",
    "    return Vstar"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "def updateWb_js(U, V, W, b, alpha, rho): \n",
    "    d,N = V.size()\n",
    "    I = torch.eye(d, device=device)\n",
    "    _, col_U = U.size()\n",
    "    Wstar = torch.mm(alpha*W+rho*torch.mm(U-b.repeat(1,col_U),torch.t(V)),torch.inverse(alpha*I+rho*(torch.mm(V,torch.t(V)))))\n",
    "    bstar = (alpha*b+rho*torch.sum(U-torch.mm(W,V), dim=1).reshape(b.size()))/(rho*N+alpha)\n",
    "    return Wstar, bstar"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Define the proximal operator of the ReLU activation function"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "def relu_prox(a, b, gamma, d, N):\n",
    "    val = torch.empty(d,N, device=device)\n",
    "    x = (a+gamma*b)/(1+gamma)\n",
    "    y = torch.min(b,torch.zeros(d,N, device=device))\n",
    "\n",
    "    val = torch.where(a+gamma*b < 0, y, torch.zeros(d,N, device=device))\n",
    "    val = torch.where(((a+gamma*b >= 0) & (b >=0)) | ((a*(gamma-np.sqrt(gamma*(gamma+1))) <= gamma*b) & (b < 0)), x, val)\n",
    "    val = torch.where((-a <= gamma*b) & (gamma*b <= a*(gamma-np.sqrt(gamma*(gamma+1)))), b, val)\n",
    "    return val"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Training algorithm"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Train on 60000 samples, validate on 10000 samples\n",
      "Epoch 1 / 30 \n",
      " - time: 63.15632462501526 - sq_loss: 20131.158203125 - tot_loss: 20153.119740101974 - acc: 0.5842166666666667 - val_acc: 0.5816\n",
      "Epoch 2 / 30 \n",
      " - time: 64.48930048942566 - sq_loss: 15162.9033203125 - tot_loss: 15172.447250099853 - acc: 0.8469166666666667 - val_acc: 0.8459\n",
      "Epoch 3 / 30 \n",
      " - time: 70.73325085639954 - sq_loss: 11660.166015625 - tot_loss: 11666.232872935943 - acc: 0.9019833333333334 - val_acc: 0.9048\n",
      "Epoch 4 / 30 \n",
      " - time: 66.16476559638977 - sq_loss: 9017.4794921875 - tot_loss: 9022.219353240915 - acc: 0.9200333333333334 - val_acc: 0.9198\n",
      "Epoch 5 / 30 \n",
      " - time: 64.90393686294556 - sq_loss: 6977.7626953125 - tot_loss: 6984.065168727189 - acc: 0.9291333333333334 - val_acc: 0.9281\n",
      "Epoch 6 / 30 \n",
      " - time: 63.93915915489197 - sq_loss: 5419.50830078125 - tot_loss: 5424.001744959503 - acc: 0.9338833333333333 - val_acc: 0.9335\n",
      "Epoch 7 / 30 \n",
      " - time: 63.252880573272705 - sq_loss: 4197.98291015625 - tot_loss: 4203.408054061234 - acc: 0.9380666666666667 - val_acc: 0.9384\n",
      "Epoch 8 / 30 \n",
      " - time: 63.815290212631226 - sq_loss: 3257.245361328125 - tot_loss: 3261.3149085035548 - acc: 0.9412 - val_acc: 0.9395\n",
      "Epoch 9 / 30 \n",
      " - time: 64.16407537460327 - sq_loss: 2530.836181640625 - tot_loss: 2534.642513083294 - acc: 0.9439833333333333 - val_acc: 0.9418\n",
      "Epoch 10 / 30 \n",
      " - time: 66.7871835231781 - sq_loss: 1958.2674560546875 - tot_loss: 1961.9273851457983 - acc: 0.9462166666666667 - val_acc: 0.9435\n",
      "Epoch 11 / 30 \n",
      " - time: 67.4346752166748 - sq_loss: 1520.2000732421875 - tot_loss: 1524.1200939193368 - acc: 0.9482333333333334 - val_acc: 0.9446\n",
      "Epoch 12 / 30 \n",
      " - time: 64.80468964576721 - sq_loss: 1180.431640625 - tot_loss: 1184.1284234710038 - acc: 0.9502833333333334 - val_acc: 0.9454\n",
      "Epoch 13 / 30 \n",
      " - time: 63.304046630859375 - sq_loss: 913.5596313476562 - tot_loss: 917.0244833156466 - acc: 0.9519 - val_acc: 0.9469\n",
      "Epoch 14 / 30 \n",
      " - time: 63.24385213851929 - sq_loss: 709.2149658203125 - tot_loss: 712.4112855792046 - acc: 0.9534833333333333 - val_acc: 0.9485\n",
      "Epoch 15 / 30 \n",
      " - time: 63.23803782463074 - sq_loss: 550.2128295898438 - tot_loss: 553.8654352463782 - acc: 0.9548 - val_acc: 0.9498\n",
      "Epoch 16 / 30 \n",
      " - time: 63.85797691345215 - sq_loss: 426.2735290527344 - tot_loss: 429.9393789358437 - acc: 0.956 - val_acc: 0.9506\n",
      "Epoch 17 / 30 \n",
      " - time: 68.13866639137268 - sq_loss: 331.0276794433594 - tot_loss: 334.3836557865143 - acc: 0.9566 - val_acc: 0.9512\n",
      "Epoch 18 / 30 \n",
      " - time: 65.138827085495 - sq_loss: 256.45361328125 - tot_loss: 259.58827410265803 - acc: 0.9576 - val_acc: 0.9517\n",
      "Epoch 19 / 30 \n",
      " - time: 63.65900754928589 - sq_loss: 198.9855499267578 - tot_loss: 201.8544980622828 - acc: 0.9583333333333334 - val_acc: 0.9529\n",
      "Epoch 20 / 30 \n",
      " - time: 64.46108770370483 - sq_loss: 154.54469299316406 - tot_loss: 157.39510209485888 - acc: 0.95925 - val_acc: 0.9535\n",
      "Epoch 21 / 30 \n",
      " - time: 63.19001746177673 - sq_loss: 119.7060317993164 - tot_loss: 123.07049903459847 - acc: 0.9596833333333333 - val_acc: 0.9541\n",
      "Epoch 22 / 30 \n",
      " - time: 63.20848870277405 - sq_loss: 92.91520690917969 - tot_loss: 96.60481747612357 - acc: 0.9605833333333333 - val_acc: 0.9541\n",
      "Epoch 23 / 30 \n",
      " - time: 63.929826974868774 - sq_loss: 72.1488265991211 - tot_loss: 75.50542926415801 - acc: 0.9607333333333333 - val_acc: 0.9542\n",
      "Epoch 24 / 30 \n",
      " - time: 63.13680863380432 - sq_loss: 55.91535186767578 - tot_loss: 58.73839760757983 - acc: 0.9615833333333333 - val_acc: 0.955\n",
      "Epoch 25 / 30 \n",
      " - time: 64.40865540504456 - sq_loss: 43.419822692871094 - tot_loss: 45.93652200978249 - acc: 0.9618 - val_acc: 0.955\n",
      "Epoch 26 / 30 \n",
      " - time: 63.778149366378784 - sq_loss: 33.696319580078125 - tot_loss: 37.25523943081498 - acc: 0.9623333333333334 - val_acc: 0.9548\n",
      "Epoch 27 / 30 \n",
      " - time: 63.43364977836609 - sq_loss: 26.14389419555664 - tot_loss: 28.918772308155894 - acc: 0.9627333333333333 - val_acc: 0.9549\n",
      "Epoch 28 / 30 \n",
      " - time: 63.21438980102539 - sq_loss: 20.3102970123291 - tot_loss: 23.51432328298688 - acc: 0.9633333333333334 - val_acc: 0.9557\n",
      "Epoch 29 / 30 \n",
      " - time: 66.83371329307556 - sq_loss: 15.755707740783691 - tot_loss: 19.28920467849821 - acc: 0.9630666666666666 - val_acc: 0.956\n",
      "Epoch 30 / 30 \n",
      " - time: 66.48925828933716 - sq_loss: 12.236991882324219 - tot_loss: 15.04707515379414 - acc: 0.9633333333333334 - val_acc: 0.9564\n"
     ]
    }
   ],
   "source": [
    "# Iterations\n",
    "print('Train on', N, 'samples, validate on', N_test, 'samples')\n",
    "for k in range(niter):\n",
    "    start = time.time()\n",
    "\n",
    "    # update V4\n",
    "    V4 = (y_one_hot + gamma4*U4 + alpha1*V4)/(1 + gamma4 + alpha1)\n",
    "    \n",
    "    # update U4 \n",
    "    U4 = (gamma4*V4 + rho4*(torch.mm(W4,V3) + b4.repeat(1,N)))/(gamma4 + rho4)\n",
    "\n",
    "    # update W4 and b4\n",
    "    W4, b4 = updateWb_js(U4,V3,W4,b4,alpha2,rho4)\n",
    "    \n",
    "    # update V3\n",
    "    V3 = updateV_js(U3,U4,W4,b4,rho4,gamma3)\n",
    "    \n",
    "    # update U3\n",
    "    U3 = relu_prox(V3,(rho3*torch.addmm(b3.repeat(1,N), W3, V2) + alpha3*U3)/(rho3 + alpha3),(rho3 + alpha3)/gamma3,d3,N)\n",
    "    \n",
    "    # update W3 and b3\n",
    "    W3, b3 = updateWb_js(U3,V2,W3,b3,alpha4,rho3)\n",
    "    \n",
    "    # update V2\n",
    "    V2 = updateV_js(U2,U3,W3,b3,rho3,gamma2)\n",
    "    \n",
    "    # update U2\n",
    "    U2 = relu_prox(V2,(rho2*torch.addmm(b2.repeat(1,N), W2, V1) + alpha5*U2)/(rho2 + alpha5),(rho2 + alpha5)/gamma2,d2,N)\n",
    "    \n",
    "    # update W2 and b2\n",
    "    W2, b2 = updateWb_js(U2,V1,W2,b2,alpha6,rho2)\n",
    "\n",
    "    # update V1\n",
    "    V1 = updateV_js(U1,U2,W2,b2,rho2,gamma1)\n",
    "    \n",
    "    # update U1\n",
    "    U1 = relu_prox(V1,(rho1*torch.addmm(b1.repeat(1,N), W1, x_train) + alpha7*U1)/(rho1 + alpha7),(rho1 + alpha7)/gamma1,d1,N)\n",
    "\n",
    "    # update W1 and b1\n",
    "    W1, b1 = updateWb_js(U1,x_train,W1,b1,alpha8,rho1)\n",
    "\n",
    "    a1_train = nn.ReLU()(torch.addmm(b1.repeat(1, N), W1, x_train))\n",
    "    a2_train = nn.ReLU()(torch.addmm(b2.repeat(1, N), W2, a1_train))\n",
    "    a3_train = nn.ReLU()(torch.addmm(b3.repeat(1, N), W3, a2_train))\n",
    "    pred = torch.argmax(torch.addmm(b4.repeat(1, N), W4, a3_train), dim=0)\n",
    "\n",
    "    a1_test = nn.ReLU()(torch.addmm(b1.repeat(1, N_test), W1, x_test))\n",
    "    a2_test = nn.ReLU()(torch.addmm(b2.repeat(1, N_test), W2, a1_test))\n",
    "    a3_test = nn.ReLU()(torch.addmm(b3.repeat(1, N_test), W3, a2_test))\n",
    "    pred_test = torch.argmax(torch.addmm(b4.repeat(1, N_test), W4, a3_test), dim=0)\n",
    "    \n",
    "    loss1[k] = gamma4/2*torch.pow(torch.dist(V4,y_one_hot,2),2).cpu().numpy()\n",
    "    loss2[k] = loss1[k] + rho1/2*torch.pow(torch.dist(torch.addmm(b1.repeat(1,N), W1, x_train),U1,2),2).cpu().numpy() \\\n",
    "    +rho2/2*torch.pow(torch.dist(torch.addmm(b2.repeat(1,N), W2, V1),U2,2),2).cpu().numpy() \\\n",
    "    +rho3/2*torch.pow(torch.dist(torch.addmm(b3.repeat(1,N), W3, V2),U3,2),2).cpu().numpy() \\\n",
    "    +rho4/2*torch.pow(torch.dist(torch.addmm(b4.repeat(1,N), W4, V3),U4,2),2).cpu().numpy()\n",
    "    \n",
    "    # compute training accuracy\n",
    "    correct_train = pred == y_train\n",
    "    accuracy_train[k] = np.mean(correct_train.cpu().numpy())\n",
    "    \n",
    "    # compute validation accuracy\n",
    "    correct_test = pred_test == y_test\n",
    "    accuracy_test[k] = np.mean(correct_test.cpu().numpy())\n",
    "    \n",
    "    # compute training time\n",
    "    stop = time.time()\n",
    "    duration = stop - start\n",
    "    time1[k] = duration\n",
    "    \n",
    "    # print results\n",
    "    print('Epoch', k + 1, '/', niter, '\\n', \n",
    "          '-', 'time:', time1[k], '-', 'sq_loss:', loss1[k], '-', 'tot_loss:', loss2[k], \n",
    "          '-', 'acc:', accuracy_train[k], '-', 'val_acc:', accuracy_test[k])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Visualization of training results"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Text(0.5,1,'validation accuracy')"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.figure()\n",
    "plt.plot(np.arange(1,niter+1), loss2)\n",
    "plt.title('training loss')\n",
    "\n",
    "plt.figure()\n",
    "plt.plot(np.arange(1,niter+1), accuracy_test)\n",
    "plt.title('validation accuracy')"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
